package yhao.infra.feature.aliyun.oss.type;

import java.util.*;

/**
 * 枚举定义W_weight_height，有水印宽、高
 * 枚举定义weight_height，无水印宽、高
 * @author yoara
 * <p> Created on 2019/3/22 </p>
 */
public class AliyunOssImgTypeHelper {

    public static void main(String[] args) {
        AliyunOssImgTypeParam param = new AliyunOssImgTypeParam(true,600,800);
        System.out.println(selectType(param));
    }

    /**
     * 根据样式获取最接近的样式配置
     * @param param
     * @return
     */
    public static AliyunOssImgType selectType(AliyunOssImgTypeParam param) {
        AliyunOssImgType type = AliyunOssImgCommonType.W_NORMAL;
        if(param.getHeight()>0){
            Map<Integer,Map<Integer, AliyunOssImgType>> heightMap =
                    param.isWaterMark()? W_TYPE_MAP : N_TYPE_MAP;
            if(heightMap.size()>0){
                Map<Integer, AliyunOssImgType> weightMap;
                List<Integer> heightList = type.isWaterMark()? W_HEIGHT_SORT_LIST : N_HEIGHT_SORT_LIST;
                int height = pickNearest(param.getHeight(),heightList);
                weightMap = heightMap.get(height);
                if(weightMap!=null){
                    if(param.getWeight()>0){
                        Map<Integer,ArrayList<Integer>> weightSortMap =
                                type.isWaterMark()? W_WEIGHT_SORT_MAP : N_WEIGHT_SORT_MAP;
                        if(weightSortMap.size()>0){
                            int weight = pickNearest(param.getWeight(),weightSortMap.get(height));
                            type = weightMap.get(weight);
                        }
                    }else{
                        type = weightMap.values().iterator().next();
                    }
                }
            }
        }
        return type;
    }

    private static int pickNearest(int key, List<Integer> list) {
        int low = 0;
        int high = list.size();
        int nearest = 0;
        int gap = 99999;
        while (low <= high) {
            int mid = (low + high) >>> 1;
            if(mid>=list.size()){
                break;
            }
            int midVal = list.get(mid);
            //计算差值
            int thisGap = Math.abs(key-midVal);
            if(thisGap<gap){
                nearest = midVal;
                gap = thisGap;
            }

            if (midVal < key){
                low = mid + 1;
            }else if (midVal > key){
                high = mid - 1;
            } else{
                break;
            }
        }
        return nearest;
    }

    //W包含水印样式
    private static Map<Integer,Map<Integer, AliyunOssImgType>> W_TYPE_MAP = new HashMap<>();
    //N不包含水印样式
    private static Map<Integer,Map<Integer, AliyunOssImgType>> N_TYPE_MAP = new HashMap<>();

    private static ArrayList<Integer> W_HEIGHT_SORT_LIST = new ArrayList<>();
    private static ArrayList<Integer> N_HEIGHT_SORT_LIST = new ArrayList<>();

    private static Map<Integer,ArrayList<Integer>> W_WEIGHT_SORT_MAP = new HashMap<>();
    private static Map<Integer,ArrayList<Integer>> N_WEIGHT_SORT_MAP = new HashMap<>();

    //空间换时间
    public static void initHelper(List<AliyunOssImgType> values){
        W_TYPE_MAP = new HashMap<>();
        N_TYPE_MAP = new HashMap<>();
        W_HEIGHT_SORT_LIST = new ArrayList<>();
        N_HEIGHT_SORT_LIST = new ArrayList<>();
        W_WEIGHT_SORT_MAP = new HashMap<>();
        N_WEIGHT_SORT_MAP = new HashMap<>();
        if(values==null){
            values = Arrays.asList(AliyunOssImgCommonType.values());
        }
        for(AliyunOssImgType type:values){
            if(type.getHeight()>0){
                //组装查询map
                Map<Integer,Map<Integer, AliyunOssImgType>> heightMap =
                        type.isWaterMark()? W_TYPE_MAP : N_TYPE_MAP;
                Map<Integer, AliyunOssImgType> weightMap = heightMap.get(type.getHeight());
                if(weightMap==null){
                    weightMap = new HashMap<>();
                    heightMap.put(type.getHeight(),weightMap);
                }
                weightMap.put(type.getWeight(),type);
                //组装height查询list
                if(type.getHeight()>0){
                    List<Integer> heightList = type.isWaterMark()? W_HEIGHT_SORT_LIST : N_HEIGHT_SORT_LIST;
                    if(!heightList.contains(type.getHeight())){
                        heightList.add(type.getHeight());
                    }
                }
                //组装weight查询map
                Map<Integer,ArrayList<Integer>> weightSortMap =
                        type.isWaterMark()? W_WEIGHT_SORT_MAP : N_WEIGHT_SORT_MAP;
                ArrayList<Integer> weightSortList = weightSortMap.get(type.getHeight());
                if(weightSortList==null){
                    weightSortList = new ArrayList<>();
                    weightSortMap.put(type.getHeight(),weightSortList);
                }
                if(!weightSortList.contains(type.getWeight())){
                    weightSortList.add(type.getWeight());
                }
            }
        }
        W_HEIGHT_SORT_LIST.sort((o1, o2) -> o1>o2?1:-1);
        N_HEIGHT_SORT_LIST.sort((o1, o2) -> o1>o2?1:-1);
        for(Map.Entry<Integer,ArrayList<Integer>> entry:W_WEIGHT_SORT_MAP.entrySet()){
            entry.getValue().sort((o1, o2) -> o1>o2?1:-1);
        }
        for(Map.Entry<Integer,ArrayList<Integer>> entry:N_WEIGHT_SORT_MAP.entrySet()){
            entry.getValue().sort((o1, o2) -> o1>o2?1:-1);
        }
    }
}
